Unit BDojoWebUnit;

{$mode objfpc}{$H+}{$interfaces corba}

Interface

Uses
  Classes, SysUtils, fgl, BDojoSessionUnit, BDijitWidgetUnit,
    BDijitLayoutWidgetUnit, BDojoxFloatingPaneUnit, BDijitContentPaneUnit,
    BDijitBorderContainerUnit, BDijitButtonUnit, BDijitTextBoxUnit,
    BDojoJsonRestUnit, BDojoObjectStoreUnit, BDojoxDataGridUnit,
    BDojoItemFileWriteStoreUnit, BDojoxGridContainerLiteUnit,
    BDojoxTableContainerUnit;

Const
  lyBorder = 'border';
  lyGrid = 'grid';
  lyTable = 'table';

  rgCenter = 'center';
  rgTop = 'top';
  rgLeft = 'left';
  rgRight = 'right';
  rgBottom = 'bottom';

Type IPlaceableInterface = Interface
  Function GetSession: BDojoSessionClass;
  Procedure Place(Const aObject: BDijitWidgetClass);
End;

Type

{ BWebLayoutTableClass }

BWebLayoutTableClass = Class(BDojoxTableContainerClass, IPlaceableInterface)
  Private
    Function GetSession: BDojoSessionClass; Inline;
    Procedure Place(Const aObject: BDijitWidgetClass); Inline;
  Public
    Constructor Build(Const aMaster: IPlaceableInterface;
      Const aRegion: String = '');
End;

Type

{ BWebLayoutGridClass }

BWebLayoutGridClass = Class(BDojoxGridContainerLiteClass, IPlaceableInterface)
  Private
    Function GetSession: BDojoSessionClass; Inline;
    Procedure Place(Const aObject: BDijitWidgetClass); Inline;
  Public
    Constructor Build(Const aMaster: IPlaceableInterface;
      Const aRegion: String = '');
End;

Type

{ BWebPanelClass }

 BWebPanelClass = Class(BDijitContentPaneClass, IPlaceableInterface)
  Private
    bLayout: String;
    bLayoutWidget: BDijitLayoutWidgetClass;
    Function GetSession: BDojoSessionClass;
    Procedure Place(Const aObject: BDijitWidgetClass);
    Procedure SetLayout(aValue: String);
  Public
    Property Layout: String Read bLayout Write SetLayout;
    Property LayoutWidget: BDijitLayoutWidgetClass Read bLayoutWidget;
    Constructor Build(Const aMaster: IPlaceableInterface;
      Const aRegion: String = ''; Const aLayout: String = '');
End;

Type

{ BWebButtonClass }

 BWebButtonClass = Class(BDijitButtonClass)
  Private
  Public
    Constructor Build(Const aMaster: IPlaceableInterface;
      Const aFieldLabel: String);
    Constructor Build(Const aMaster: IPlaceableInterface;
      Const aFieldLabel: String; Const aMethod: BProcedureClass);
    Constructor Build(Const aMaster: IPlaceableInterface;
      Const aFieldLabel: String; Const aMethod: BProcedureClass;
      Const aParams: Array Of String);
    Constructor Build(Const aMaster: IPlaceableInterface;
      Const aFieldLabel: String; Const aJSCode: String);
    Constructor Build(Const aMaster: IPlaceableInterface;
      Const aFieldLabel: String; Const aJSCodeMask: String;
      Const aParams: Array Of Const);
End;

Type

{ BWebEditClass }

 BWebEditClass = Class(BDijitTextBoxClass)
  Private
  Public
    Constructor Build(Const aMaster: IPlaceableInterface;
      Const aFieldLabel: String);
End;

//TODO: Change for Enchanced grid
//TODO: add BWebGridFieldClass for "invisible" columns
Type

{ BWebGridClass }

 BWebGridClass = Class(BDojoxDataGridClass)
  Type

  { BWebGridColumnClass }

 BWebGridColumnClass = Class
    Private
      bName, bField: String;
      bWidth: Integer;
      Function GetJSON: String;
    Public
      Property JSON: String Read GetJSON;
      Constructor Build(Const aName, aField: String; Const aWidth: Integer);
      Destructor Burn;
  End;
  Type BWebGridColumntsList = Specialize TFPGList<BWebGridColumnClass>;
  Private
    bColumns: BWebGridColumntsList;
    Procedure BeforeInitialization; override;
  Public
    Procedure AddColumn(Const aName, aField: String;
      Const aWidth: Integer);
    Constructor Build(Const aMaster: IPlaceableInterface;
      Const aGetter: BFunctionClass; Const aPath: String = '';
      Const aRegion: String = '');
    Destructor Burn; override;
End;

Type

{ BWebRibbonClass }

 BWebRibbonClass = Class(BDijitContentPaneClass)
  Private
    bLayout: BDojoxGridContainerLiteClass;
  Public
    Constructor Build(Const aMaster: IPlaceableInterface);
End;

Type

{ BWebFormClass }

BWebFormClass = Class(BDojoxFloatingPaneClass, IPlaceableInterface)
  Private
    bLayout: String;
    bLayoutBorder: BDijitBorderContainerClass;
    bLayoutGrid: BDojoxGridContainerLiteClass;
    bLayoutTable: BDojoxTableContainerClass;
    bLayoutWidget: BDijitLayoutWidgetClass;
    Procedure SetLayout(aValue: String);
    Function GetSession: BDojoSessionClass;
    Procedure Place(Const aObject: BDijitWidgetClass);
  Public
    //** QuickInitialization of LayoutWidget
    Property Layout: String Read bLayout Write SetLayout;
    //** LayoutWidget available on Layout specific
    Property LayoutWidget: BDijitLayoutWidgetClass Read bLayoutWidget;

    //** Available on layout is lyBorder
    Property LayoutBorder: BDijitBorderContainerClass Read bLayoutBorder;
    //** Available on layout is lyGrid
    Property LayoutGrid: BDojoxGridContainerLiteClass Read bLayoutGrid;
    //** Available on layout is lyTable
    Property LayoutTable: BDojoxTableContainerClass Read bLayoutTable;

    Procedure AddItem(Const aWidget: BDijitWidgetClass);
    Constructor Build(Const aSession: BDojoSessionClass;
      Const aWidth, aHeight: Integer; Const aLayout: String = '');
    Destructor Burn; Override;
End;

Type

{ BWebViewportClass }

BWebViewportClass = Class(BDijitContentPaneClass, IPlaceableInterface)
  Private
    bLayout: String;
    bLayoutBorder: BDijitBorderContainerClass;
    bLayoutGrid: BDojoxGridContainerLiteClass;
    bLayoutTable: BDojoxTableContainerClass;
    bLayoutWidget: BDijitLayoutWidgetClass;
    Function GetSession: BDojoSessionClass;
    Procedure Place(Const aObject: BDijitWidgetClass);
    Procedure SetLayout(aValue: String);
  Public
    //** QuickInitialization of LayoutWidget
    Property Layout: String Read bLayout Write SetLayout;
    //** LayoutWidget available on Layout specific
    Property LayoutWidget: BDijitLayoutWidgetClass Read bLayoutWidget;

    //** Available on layout is lyBorder
    Property LayoutBorder: BDijitBorderContainerClass Read bLayoutBorder;
    //** Available on layout is lyGrid
    Property LayoutGrid: BDojoxGridContainerLiteClass Read bLayoutGrid;
    //** Available on layout is lyTable
    Property LayoutTable: BDojoxTableContainerClass Read bLayoutTable;

    Constructor Build(Const aSession: BDojoSessionClass;
      Const aLayout: String = '');
End;

Implementation

Procedure SetPlaceableLayout(Const aLayout: String;
  Const aInstance: BDijitContentPaneClass;
  Var aLayoutWidget: BDijitLayoutWidgetClass);
Begin
  If Not(aLayoutWidget = nil) Then
    Raise Exception.Create('Unable change layout on fly');
  Case aLayout Of
    lyBorder:
      aLayoutWidget := BDijitBorderContainerClass.Build(aInstance.Session);
    lyGrid:
      aLayoutWidget := BDojoxGridContainerLiteClass.Build(aInstance.Session);
    lyTable:
      aLayoutWidget := BDojoxTableContainerClass.Build(aInstance.Session);
  End;
  aInstance.ContentObj := aLayoutWidget;
End;

{ BWebRibbonClass }

Constructor BWebRibbonClass.Build(Const aMaster: IPlaceableInterface);
Begin
  Inherited Build(aMaster.GetSession);
  Style := 'height: 100px;';
  aMaster.Place(Self);
  bLayout := BDojoxGridContainerLiteClass.Build(Session);
  bLayout.Startup;
  bLayout.DisableDnD;
  ContentObj := bLayout;
  Region := rgTop;
End;

{ BWebViewportClass }

Function BWebViewportClass.GetSession: BDojoSessionClass;
Begin
  Result := Session;
End;

Procedure BWebViewportClass.Place(Const aObject: BDijitWidgetClass);
Begin
  If LayoutWidget = nil Then ContentObj := aObject
  Else LayoutWidget.AddChild(aObject);
End;

Procedure BWebViewportClass.SetLayout(aValue: String);
Begin
  SetPlaceableLayout(aValue, Self, bLayoutWidget);
  Case aValue Of
    lyBorder: bLayoutBorder := BDijitBorderContainerClass(bLayoutWidget);
    lyGrid: bLayoutGrid := BDojoxGridContainerLiteClass(bLayoutWidget);
    lyTable: bLayoutTable := BDojoxTableContainerClass(bLayoutWidget);
  End;
End;

Constructor BWebViewportClass.Build(Const aSession: BDojoSessionClass;
  Const aLayout: String);
Begin
  Inherited Build(aSession);
  ID := BuildDynamicElement;
  bSrcNodeRef := ID;
  Style := 'width: 100%; height: 100%;';
  If Not(aLayout = '') Then Layout := aLayout;
End;

{ BWebLayoutTableClass }

Function BWebLayoutTableClass.GetSession: BDojoSessionClass;
Begin
  Result := Session;
End;

Procedure BWebLayoutTableClass.Place(Const aObject: BDijitWidgetClass);
Begin
  AddChild(aObject);
End;

Constructor BWebLayoutTableClass.Build(Const aMaster: IPlaceableInterface;
  Const aRegion: String);
Begin
  Inherited Build(aMaster.GetSession);
  aMaster.Place(Self);
  If Not(aRegion = '') Then Region := aRegion;
End;

{ BWebLayoutGridClass }

Function BWebLayoutGridClass.GetSession: BDojoSessionClass;
Begin
  Result := Session;
End;

Procedure BWebLayoutGridClass.Place(Const aObject: BDijitWidgetClass);
Begin
  AddChild(aObject, -1);
End;

Constructor BWebLayoutGridClass.Build(Const aMaster: IPlaceableInterface;
  Const aRegion: String);
Begin
  Inherited Build(aMaster.GetSession);
  aMaster.Place(Self);
  If Not(aRegion = '') Then Region := aRegion;
End;

{ BWebEditClass }

Constructor BWebEditClass.Build(Const aMaster: IPlaceableInterface;
  Const aFieldLabel: String);
Begin
  Inherited Build(aMaster.GetSession);
  aMaster.Place(Self);
  If Not(aFieldLabel = '') Then
    FieldLabel := aFieldLabel;
End;

{ BWebGridClass.BWebGridColumnClass }

Function BWebGridClass.BWebGridColumnClass.GetJSON: String;
Begin
  Result := Format('{name:"%s",field:"%s",width:"%dpx"}',
    [bName, bField, bWidth]);
end;

Constructor BWebGridClass.BWebGridColumnClass.Build(Const aName,
  aField: String; Const aWidth: Integer);
Begin
  bName := aName;
  bField := aField;
  bWidth := aWidth;
End;

Destructor BWebGridClass.BWebGridColumnClass.Burn;
Begin

End;

{ BWebGridClass }

Procedure BWebGridClass.BeforeInitialization;
Var
  i: Integer;
  aStructure: String;
Begin
  If bColumns.Count = 0 Then
    Raise Exception.Create('Unable initialize Data Grid without columns');
  For i := 0 To bColumns.Count - 1 Do
    aStructure += ',' + bColumns[i].JSON;
  //Dirty workaround
  If aStructure[1] = ',' Then Delete(aStructure, 1, 1);
  Structure := '[' + aStructure + ']';
End;

Procedure BWebGridClass.AddColumn(Const aName, aField: String;
  Const aWidth: Integer);
Begin
  bColumns.Add(BWebGridColumnClass.Build(aName, aField, aWidth));
End;

Constructor BWebGridClass.Build(Const aMaster: IPlaceableInterface;
  Const aGetter: BFunctionClass; Const aPath: String; Const aRegion: String);
Var
  aJSONRest: BDojoJsonRestClass;
  aStore: BDojoObjectStoreClass;
Begin
  Inherited Build(aMaster.GetSession);

  bColumns := BWebGridColumntsList.Create;

  // Prepare connection of grid and jsonrest
  aJSONRest := BDojoJsonRestClass.Build(aMaster.GetSession);
  aJSONRest.Target := 'location.href +"/' +
    Session.RegisterHandler(aPath, aGetter) + '"';
  aStore := BDojoObjectStoreClass.Build(aMaster.GetSession);
  aStore.ObjectStore := aJSONRest;
  Store := aStore;
  aMaster.Place(Self);
  Region := aRegion;
End;

Destructor BWebGridClass.Burn;
Begin
  Inherited Burn;
End;

{ BWebPanelClass }

Function BWebPanelClass.GetSession: BDojoSessionClass;
Begin
  Result := Session;
End;

Procedure BWebPanelClass.Place(Const aObject: BDijitWidgetClass);
Begin
  If Assigned(bLayoutWidget) Then bLayoutWidget.AddChild(aObject)
  Else ContentObj := aObject;
End;

Procedure BWebPanelClass.SetLayout(aValue: String);
Begin
  If bLayout = aValue Then Exit;
  bLayout := aValue;

  If Not(bLayoutWidget = nil) Then
    bLayoutWidget.Burn;
  Case bLayout Of
    lyBorder: bLayoutWidget := BDijitBorderContainerClass.Build(Session);
  End;
  ContentObj := bLayoutWidget;
End;

Constructor BWebPanelClass.Build(Const aMaster: IPlaceableInterface;
  Const aRegion: String; Const aLayout: String);
Begin
  Inherited Build(aMaster.GetSession);
  aMaster.Place(Self);
  If Not(aRegion = '') Then Region := aRegion;
  If Not(aLayout = '') Then Layout := aLayout;
End;

{ BWebButtonClass }

Constructor BWebButtonClass.Build(Const aMaster: IPlaceableInterface;
  Const aFieldLabel: String);
Begin
  Inherited Build(aMaster.GetSession);
  FieldLabel := aFieldLabel;
  aMaster.Place(Self);
End;

Constructor BWebButtonClass.Build(Const aMaster: IPlaceableInterface;
  Const aFieldLabel: String; Const aMethod: BProcedureClass);
Begin
  Build(aMaster, aFieldLabel, aMethod, []);
End;

Constructor BWebButtonClass.Build(Const aMaster: IPlaceableInterface;
  Const aFieldLabel: String; Const aMethod: BProcedureClass;
  Const aParams: Array Of String);
Begin
  Build(aMaster, aFieldLabel);
  If Not(aMethod = nil) Then
    Listen('click', aMethod, aParams);
End;

Constructor BWebButtonClass.Build(Const aMaster: IPlaceableInterface;
  Const aFieldLabel: String; Const aJSCode: String);
Begin
  Build(aMaster, aFieldLabel);
  Listen('click', aJSCode);
End;

Constructor BWebButtonClass.Build(Const aMaster: IPlaceableInterface;
  Const aFieldLabel: String; Const aJSCodeMask: String;
  Const aParams: Array Of Const);
Begin
  Build(aMaster, aFieldLabel, Format(aJSCodeMask, aParams));
End;

{ BWebFormClass }

Procedure BWebFormClass.SetLayout(aValue: String);
Begin
  SetPlaceableLayout(aValue, Self, bLayoutWidget);
  Case aValue Of
    lyBorder: bLayoutBorder := BDijitBorderContainerClass(bLayoutWidget);
    lyGrid: bLayoutGrid := BDojoxGridContainerLiteClass(bLayoutWidget);
    lyTable: bLayoutTable := BDojoxTableContainerClass(bLayoutWidget);
  End;
End;

Function BWebFormClass.GetSession: BDojoSessionClass;
Begin
  Result := Session;
End;

//TODO: clean. Add behavior on replace value of ContentObj
Procedure BWebFormClass.Place(Const aObject: BDijitWidgetClass);
Begin
  If LayoutWidget = nil Then ContentObj := aObject
  Else LayoutWidget.AddChild(aObject);
End;

Procedure BWebFormClass.AddItem(Const aWidget: BDijitWidgetClass);
Begin
  If Not(bLayoutWidget = nil) Then
    bLayoutWidget.AddChild(aWidget);
End;

Constructor BWebFormClass.Build(Const aSession: BDojoSessionClass;
  Const aWidth, aHeight: Integer; Const aLayout: String);
Begin
  Inherited Build(aSession);
  Style := Format('width: %dpx; height: %dpx;', [aWidth, aHeight]);
  If Not(aLayout = '') Then
    Layout := aLayout;
End;

Destructor BWebFormClass.Burn;
Begin
  Inherited;
End;

End.

